#include "qcom_common.h"
#include "swat_wmiconfig_common.h"
#include "swat_parse.h"
#include "qcom/socket_api.h"
#include "swat_bench_core.h"
#include "swat_bench_iniche_1.1.2.h"
#include "swat_wmiconfig_p2p.h"
#include "qcom/qcom_ssl.h"
#include "qcom/qcom_scan.h"
#include "hwcrypto_api.h"
#include "malloc_api.h"
#include "qcom/qcom_gpio.h"
#include "string.h"

#define EXAMPLE_WIFI_SSID "dlink_four"
#define EXAMPLE_WIFI_PASS "gree@2019"

#define SERVER_STR_ADDR "172.28.5.235"
A_UINT32 server_str_addr = 0xAC1C05EB;
#define SERVER_PORT 8366

#define SEND_BLOCK_SIZE 1024
#define SEND_BLOCK_NUM 10

#define CLIENT_HDLE_INVL_USEC 40000

#define SOCKET_WIN_SIZE 4096

#define PRINTF(fmt, ...) do{\
        printf("I {line %d}[%lu]: " fmt "\n", __LINE__, time_ms(), ##__VA_ARGS__);\
    } while(0)
#define PERROR() printf("E {line %d}\n", __LINE__)

static char s_recv_buff[SEND_BLOCK_SIZE] = {0};

A_UINT8 device_id = 0;

static void initialise_wifi(void)
{
    swat_wmiconfig_wep_passowrd_set(device_id, EXAMPLE_WIFI_PASS);
    swat_wmiconfig_wpa_set(device_id, "1", "TKIP", "TKIP");
    swat_wmiconfig_connect_ssid(device_id, EXAMPLE_WIFI_SSID);
    swat_wmiconfig_ipdhcp(device_id);
}

static void deinitialise_wifi(void)
{
    qcom_dhcps_release_pool(device_id);
    swat_wmiconfig_connect_disc(device_id);
}

void tcp_flow_ctrl_test_client()
{
    initialise_wifi();
    qcom_thread_msleep(10000);
    int recv_bytes_cnt = 0;
    int send_bytes_cnt = 0;

    int client_fd = qcom_socket(AF_INET, SOCK_STREAM, 0);
    int win_size = SOCKET_WIN_SIZE;
    int ret = qcom_setsockopt(client_fd, SOL_SOCKET, SO_RCVBUF, &win_size, sizeof(win_size));
    if(0 > ret)
    {
        PERROR();
        goto fail;
    }
    // ret = setsockopt(client_fd, SOL_SOCKET, SO_SNDBUF, &win_size, sizeof(win_size));
    // if(0 > ret)
    // {
    //     PERROR();
    //     goto fail;
    // }
    PRINTF("server ip: 0x%lX", htonl(server_str_addr));
    struct sockaddr_in server_addr = 
    {
        .sin_family = AF_INET,
        .sin_addr.s_addr = htonl(server_str_addr),
        .sin_port = htons(SERVER_PORT),
    };
    ret = qcom_connect(client_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
    if(0 > ret)
    {
        PERROR();
        goto fail;
    }
    PRINTF("tcp flow control test client start");
    unsigned long start, end, intvl;
    start = time_ms();
    while(1)
    {
        int bytes_in_block = 0;
        while(bytes_in_block < SEND_BLOCK_SIZE)
        {
            int bytes = qcom_recv(client_fd, s_recv_buff + bytes_in_block, SEND_BLOCK_SIZE - bytes_in_block, 0);
            if(bytes > 0)
            {
                // PRINTF("recv %d bytes once", bytes);
                bytes_in_block += bytes;
                recv_bytes_cnt += bytes;
            }
            else if(0 == bytes)
            {
                PRINTF("server close socket");
                goto success;
            }
            else
            {
                PERROR();
                goto fail;
            }
        }
        // PRINTF("recv one block");
        qcom_thread_msleep(CLIENT_HDLE_INVL_USEC / 1000);
        bytes_in_block = 0;
        while(bytes_in_block < SEND_BLOCK_SIZE)
        {
            int bytes = qcom_send(client_fd, s_recv_buff + bytes_in_block, SEND_BLOCK_SIZE - bytes_in_block, 0);
            if(bytes > 0)
            {
                bytes_in_block += bytes;
                send_bytes_cnt += bytes;
            }
            else if(0 == bytes)
            {
                PRINTF("send 0 bytes");
            }
            else
            {
                PRINTF("send fail: %d", bytes);
                qcom_thread_msleep(1);
            }
        }
        // PRINTF("send one block");
    }

success:
    end = time_ms();
    intvl = end - start;
    PRINTF("sum of recv %d bytes", recv_bytes_cnt);
    PRINTF("sum of send %d bytes", send_bytes_cnt);
    PRINTF("tcp flow control test client end spend %lu mili Sec", intvl);
    qcom_socket_close(client_fd);

    qcom_thread_msleep(1000);
    deinitialise_wifi();
    PRINTF("FIN");
    return;
fail:
    if(client_fd > 0)
    {
        qcom_socket_close(client_fd);
    }

    qcom_thread_msleep(1000);
    deinitialise_wifi();
    PRINTF("FIN");
    return;
}
